<?php
/**
 * DynamicChild
 * 
 * @category	Util
 * @package		dayscript.util.dynamic
 * @subpackage	
 * @author		Nelson Daza <ndaza@dayscript.com>
 * @copyright	2009 Dayscript Ltda.
 * @license		
 * @version		1.0
 * @version		$Revision: 0 $
 * @filesource	
 * @link		http://www.dayscript.com
 * @link		{docsLink}
 * @uses		
 * @since		1.0
 * @modifiedby	$LastChangedBy: Nelson Daza $
 * @modified	$Date: 2009-08-13 $
 */

namespace dayscript\util\dynamic;

/**
 * DynamicChild
 * 
 * Abstract
 * 
 * @category	Util
 * @package		dayscript.util.dynamic
 * @subpackage	
 * @author		Nelson Daza <ndaza@dayscript.com>
 * @copyright	2009 Dayscript Ltda.
 * @license		
 * @version		1.0
 * @link		http://www.dayscript.com
 * @link		{docsLink}
 * @uses		dayscript\util\dynamic\Common, \dayscript\Map, \dayscript\exception\ErrorCallerException
 * @since		1.0
 * @modifiedby	$LastChangedBy: Nelson Daza $
 * @modified	$Date: 2009-08-13 $
 */
abstract class DynamicChild extends \dayscript\util\dynamic\Common	{
	/**
	 * 
	 * @var dayscript\util\dynamic\DynamicParent $parent
	 */
	private $parent = null;
	/**
	 * 
	 * @var \dayscript\Map $parentMethods
	 */
	private $parentMethods = null;
	/**
	 * 
	 * @var \dayscript\Map $parentProperties
	 */
	private $parentProperties = null;

	/**
	 * Parent asignament
	 * @param dayscript\util\dynamic\Parent $parent
	 */
	function setParent( dayscript\util\dynamic\DynamicParent $parent )	{
		if( $this->parent !== null )
			return;
		$this->unsetParent( );
		$this->parent = $parent;
		
		$reflection = new \ReflectionClass( $parent );
		foreach( $reflection->getMethods( ) as $method )	{
			if( !$method->isPrivate( ) && \strpos( $method->getName( ), '__') !== 0 )
				$this->parentMethods[$method->getName( )] = ( $method->isPublic( ) ? 'public' : 'protected' );
		}
		foreach( $reflection->getProperties( ) as $property )	{
			if( !$method->isPrivate( ) )
				$this->parentProperties[$property->getName( )] = ( $property->isPublic( ) ? 'public' : 'protected' );
		}
	}
	/**
	 * Parent unasignament
	 */
	function unsetParent( )	{
		$this->parent = null;
		$this->parentMethods = new \dayscript\Map( );
		$this->parentProperties = new \dayscript\Map( );
	}
	/**
	 * Magic method for calling the object's methods
	 * 
	 * @param string $method
	 * @param mixed $arguments
	 * @return mixed
	 */
	function __call( $method, $args )	{
		if ( isset( $this->parentMethods[$method] ) )	{
			if( $this->parentMethods[$method] == 'public' )
				return \call_user_func_array( array( $this->parent, $method ), $args );
			return $this->parent->__callMethod( $method, $args );
		}
		throw new \dayscript\exception\ErrorCallerException( 'Call to undefined method "' . $method . '"', \E_USER_ERROR );
	}
	/**
	 * Magic method for getting the object's members values 
	 * 
	 * @param string $name
	 * @return mixed
	 */
	function __get( $name )	{
		if( isset( $this->parentProperties[$name] ) )	{
			if( $this->parentProperties[$name] == 'public' )
				return $this->parent->$name;
			return $this->parent->__getProperty($name);
		}
		throw new \dayscript\exception\ErrorCallerException( 'Call to undefined property "' . $name . '"', \E_USER_ERROR );
	}
	/**
	 * Magic method for setting the object's members values 
	 * 
	 * @param string $name
	 * @param mixed $value
	 */
	function __set( $name, $value )	{
		if( isset( $this->parentProperties[$name] ) )	{
			if( $this->parentProperties[$name] == 'public')
				$this->parent->$name = $value;
			else
				$this->parent->__setProperty( $name, $value );
		}
		else
			throw new \dayscript\exception\ErrorCallerException( 'Call to undefined property "' . $name . '"', \E_USER_ERROR );
	}
}